﻿/*
 * MessageDispenser.h
 */

#ifndef __GDK_MESSAGEDISPENSER_H__
#define __GDK_MESSAGEDISPENSER_H__


#include <gdk/core/Types.h>
#include <gdk/core/cpptypeid.h>
#include <gdk/core/Callback.h>
#include <gdk/core/Message.h>
#include <gdk/core/Exception.h>
#include <map>



namespace gdk
{



	template<typename TyReturn>
	class MessageHandler
	{
	public:
		typedef gdk::CallbackHandler<TyReturn, Message*>  CallbackHandler;

	private:
		ClassId				_classId;
		CallbackHandler		_callback;

	public:
		__INLINE__ MessageHandler(void)
		{
		}

		__INLINE__ MessageHandler(const MessageHandler &o)
			: _classId(o._classId)
			, _callback(o._callback)
		{
		}

		__INLINE__ const ClassId& getClassId(void) const
		{
			return _classId;
		}

		__INLINE__ const CallbackHandler& getCallbackHandler(void) const
		{
			return _callback;
		}

		__INLINE__ bool operator ==(const MessageHandler &o) const
		{
			return	_classId == o._classId
				&&	_callback == o._callback;
		}
		__INLINE__ bool operator !=(const MessageHandler &o) const
		{
			return !(this->operator ==(o));
		}
		__INLINE__ bool operator <(const MessageHandler &o) const
		{
			return (_classId < o._classId)
				|| (_classId == o._classId && _callback < o._callback);
		}
		__INLINE__ bool operator >(const MessageHandler &o) const
		{
			return (_classId > o._classId)
				|| (_classId == o._classId && _callback > o._callback);
		}
		__INLINE__ bool operator <=(const MessageHandler &o) const
		{
			return !(this->operator >(o));
		}
		__INLINE__ bool operator >=(const MessageHandler &o) const
		{
			return !(this->operator <(o));
		}

		__INLINE__ TyReturn operator()(Message *msg) const
		{
			return (_callback)(msg);
		}

		__INLINE__ void setNull(void)
		{
			return _callback.setNull();
		}

		__INLINE__ bool isNull(void) const
		{
			return _callback.isNull();
		}

		template<typename TyMsg>
		MessageHandler(TyReturn(*func)(TyMsg *))
			: _classId(TyMsg::getClassId_())
			, _callback(func)
		{
		}

		template<typename TyClass, typename TyMsg>
		MessageHandler(const SharedPtr<TyClass> &obj, TyReturn(TyClass::*func)(TyMsg *))
			: _classId(TyMsg::getClassId_())
			, _callback(obj, func)
		{
		}

		template<typename TyClass, typename TyMsg>
		MessageHandler(TyClass *obj, TyReturn(TyClass::*func)(TyMsg *))
			: _classId(TyMsg::getClassId_())
			, _callback(obj, func)
		{
		}

		template<typename TyClass, typename TyMsg>
		MessageHandler(const gdk::Unknown::Handle_T<TyClass> &obj, TyReturn(TyClass::*func)(TyMsg *))
			: _classId(TyMsg::getClassId_())
			, _callback(obj, func)
		{
		}

		template<typename TyClass, typename TyMsg>
		MessageHandler(TyClass &obj, TyReturn(TyClass::*func)(TyMsg *))
			: _classId(TyMsg::getClassId_())
			, _callback(obj, func)
		{
		}
		template<typename TyMsg>
		MessageHandler(const CallbackHandler &callback)
			: _classId(TyMsg::getClassId_())
			, _callback(callback)
		{
		}
	};



	template<typename TyReturn>
	class MessageDispenser
	{
	public:
		typedef typename gdk::MessageHandler<TyReturn>		MessageHandler;
		typedef typename std::map<ClassId, MessageHandler>	MessageHandlerMap;
		typedef typename MessageHandlerMap::iterator		MessageHandlerMap_Iterator;
		typedef typename MessageHandlerMap::const_iterator	MessageHandlerMap_ConstIterator;
		typedef typename MessageHandler::CallbackHandler	CallbackHandler;

	private:
		MessageHandlerMap		_mapMessageHandler;
		MessageHandler			_nullMsgHandler;

	public:
		MessageDispenser(void)
		{
		}
		~MessageDispenser(void)
		{
		}
		//-----------------------------------------------------
		TyReturn dispatchMessage(Message *msg) const __THROW1
		{
			GDK_ASSERT(msg != NULL);

			MessageHandlerMap_ConstIterator it = _mapMessageHandler.find(msg->getClassId());
			if (it != _mapMessageHandler.end())
			{
				return (it->second)(msg);
			}

			String errMsg;
			errMsg.format(__TEXT__("" STRING_FMT " MessageHandler::dispatchMessage( " STRING_FMT " )"), (const Char*)typeid_className<TyReturn>(), (const Char*)typeid_className(*msg));
			__THROW__((const Char*)errMsg);
		}
		//-----------------------------------------------------
		bool addMessageHandler(const MessageHandler &o)
		{
			GDK_ASSERT(o.getCallbackHandler() != CallbackHandler());
			GDK_ASSERT(_mapMessageHandler.find(o.getClassId()) == _mapMessageHandler.end());

			_mapMessageHandler[o.getClassId()] = o;

			return true;
		}
		void removeMessageHandler(const MessageHandler &o)
		{
			MessageHandlerMap_Iterator it = _mapMessageHandler.find(o.getClassId());
			if (it != _mapMessageHandler.end())
			{
				if (o == it->second)
				{
					_mapMessageHandler.erase(it);
				}
			}
		}
		//-----------------------------------------------------
		void clear(void)
		{
			_mapMessageHandler.clear();
		}
		//-----------------------------------------------------
		/*
		void eraseMessageHandler(const ClassId &classId)
		{
			MessageHandlerMap_Iterator it = _mapMessageHandler.find(classId);
			if (it != _mapMessageHandler.end())
			{
				_mapMessageHandler.erase(it);
			}
		}
		template<typename TyMsg>
		void eraseMessageHandler(void)
		{
			eraseMessageHandler(TyMsg().getClassId());
		}
		*/
		//-----------------------------------------------------
		template<typename TyMsg>
		bool addMessageHandler(TyReturn(*func)(TyMsg *))
		{
			return addMessageHandler(MessageHandler(func));
		}
		template<typename TyClass, typename TyMsg>
		bool addMessageHandler(const SharedPtr<TyClass> &obj, TyReturn(TyClass::*func)(TyMsg *))
		{
			return addMessageHandler(MessageHandler(obj, func));
		}
		template<typename TyClass, typename TyMsg>
		bool addMessageHandler(TyClass *obj, TyReturn(TyClass::*func)(TyMsg *))
		{
			return addMessageHandler(MessageHandler(obj, func));
		}
		template<typename TyClass, typename TyMsg>
		bool addMessageHandler(TyClass &obj, TyReturn(TyClass::*func)(TyMsg *))
		{
			return addMessageHandler(MessageHandler(obj, func));
		}
		template<typename TyClass, typename TyMsg>
		bool addMessageHandler(const gdk::Unknown::Handle_T<TyClass> &obj, TyReturn(TyClass::*func)(TyMsg *))
		{
			return addMessageHandler(MessageHandler(obj, func));
		}
		//-----------------------------------------------------
		template<typename TyMsg>
		void removeMessageHandler(TyReturn(*func)(TyMsg *))
		{
			return removeMessageHandler(MessageHandler(func));
		}
		template<typename TyClass, typename TyMsg>
		void removeMessageHandler(const SharedPtr<TyClass> &obj, TyReturn(TyClass::*func)(TyMsg *))
		{
			return removeMessageHandler(MessageHandler(obj, func));
		}
		template<typename TyClass, typename TyMsg>
		void removeMessageHandler(TyClass *obj, TyReturn(TyClass::*func)(TyMsg *))
		{
			return removeMessageHandler(MessageHandler(obj, func));
		}
		template<typename TyClass, typename TyMsg>
		void removeMessageHandler(TyClass &obj, TyReturn(TyClass::*func)(TyMsg *))
		{
			return removeMessageHandler(MessageHandler(obj, func));
		}
		template<typename TyClass, typename TyMsg>
		void removeMessageHandler(const gdk::Unknown::Handle_T<TyClass> &obj, TyReturn(TyClass::*func)(TyMsg *))
		{
			return removeMessageHandler(MessageHandler(obj, func));
		}
		//-----------------------------------------------------
		__INLINE__ MessageDispenser& operator +=(const MessageHandler &o)
		{
			addMessageHandler(o);

			return *this;
		}

		__INLINE__ MessageDispenser& operator -=(const MessageHandler &o)
		{
			removeMessageHandler(o);

			return *this;
		}
		//-----------------------------------------------------
		const MessageHandler& getMessageHandler(ClassId classId) const
		{
			MessageHandlerMap_ConstIterator it = _mapMessageHandler.find(classId);
			if (it != _mapMessageHandler.end())
			{
				return it->second;
			}
			return _nullMsgHandler;
		}

		__INLINE__ ssize_t getMessageHandlerCount(void) const
		{
			return (ssize_t)_mapMessageHandler.size();
		}
		__INLINE__ bool isMessageHandler(ClassId classId) const
		{
			return (_mapMessageHandler.find(classId) != _mapMessageHandler.end());
		}
	};






}//namespace gdk




#endif //__GDK_MESSAGEDISPENSER_H__
